Scrapy 入门教程(菜鸟教程)

分类 编程技术

Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。

Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

通常我们可以很简单的通过 Scrapy 框架实现一个爬虫,抓取指定网站的内容或图片。


Scrapy架构图(绿线是数据流向)

img

  • Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
  • Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
  • Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
  • Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).
  • Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
  • Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
  • Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)

Scrapy的运作流程

代码写好,程序开始运行...

  • 1 引擎:Hi!Spider, 你要处理哪一个网站?
  • 2 Spider:老大要我处理xxxx.com。
  • 3 引擎:你把第一个需要处理的URL给我吧。
  • 4 Spider:给你,第一个URL是xxxxxxx.com。
  • 5 引擎:Hi!调度器,我这有request请求你帮我排序入队一下。
  • 6 调度器:好的,正在处理你等一下。
  • 7 引擎:Hi!调度器,把你处理好的request请求给我。
  • 8 调度器:给你,这是我处理好的request
  • 9 引擎:Hi!下载器,你按照老大的下载中间件的设置帮我下载一下这个request请求
  • 10 下载器:好的!给你,这是下载好的东西。(如果失败:sorry,这个request下载失败了。然后引擎告诉调度器,这个request下载失败了,你记录一下,我们待会儿再下载)
  • 11 引擎:Hi!Spider,这是下载好的东西,并且已经按照老大的下载中间件处理过了,你自己处理一下(注意!这儿responses默认是交给def parse()这个函数处理的)
  • 12 Spider:(处理完毕数据之后对于需要跟进的URL),Hi!引擎,我这里有两个结果,这个是我需要跟进的URL,还有这个是我获取到的Item数据。
  • 13 引擎:Hi !管道 我这儿有个item你帮我处理一下!调度器!这是需要跟进URL你帮我处理下。然后从第四步开始循环,直到获取完老大需要全部信息。
  • 14 管道调度器:好的,现在就做!

注意!只有当调度器中不存在任何request了,整个程序才会停止,(也就是说,对于下载失败的URL,Scrapy也会重新下载。)


制作 Scrapy 爬虫 一共需要4步:

  1. 新建项目 (scrapy startproject xxx):新建一个新的爬虫项目
  2. 明确目标 (编写items.py):明确你想要抓取的目标
  3. 制作爬虫 (spiders/xxspider.py):制作爬虫开始爬取网页
  4. 存储内容 (pipelines.py):设计管道存储爬取内容

安装

Windows 安装方式

升级 pip 版本:

1
pip install --upgrade pip

通过 pip 安装 Scrapy 框架:

1
pip install Scrapy

Ubuntu 安装方式

安装非 Python 的依赖:

1
sudo apt-get install python-dev python-pip libxml2-dev libxslt1-dev zlib1g-dev libffi-dev libssl-dev

通过 pip 安装 Scrapy 框架:

1
sudo pip install scrapy

Mac OS 安装方式

对于Mac OS系统来说,由于系统本身会引用自带的python2.x的库,因此默认安装的包是不能被删除的,但是你用python2.x来安装Scrapy会报错,用python3.x来安装也是报错,我最终没有找到直接安装Scrapy的方法,所以我用另一种安装方式来说一下安装步骤,解决的方式是就是使用virtualenv来安装。

1
2
3
4
5
$ sudo pip install virtualenv
$ virtualenv scrapyenv
$ cd scrapyenv
$ source bin/activate
$ pip install Scrapy

安装后,只要在命令终端输入 scrapy,提示类似以下结果,代表已经安装成功。

img


入门案例

学习目标

  • 创建一个Scrapy项目
  • 定义提取的结构化数据(Item)
  • 编写爬取网站的 Spider 并提取出结构化数据(Item)
  • 编写 Item Pipelines 来存储提取到的Item(即结构化数据)

一. 新建项目(scrapy startproject)

在开始爬取之前,必须创建一个新的Scrapy项目。进入自定义的项目目录中,运行下列命令:

1
scrapy startproject mySpider

其中, mySpider 为项目名称,可以看到将会创建一个 mySpider 文件夹,目录结构大致如下:

下面来简单介绍一下各个主要文件的作用:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
mySpider/
    scrapy.cfg
    mySpider/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

这些文件分别是:

  • scrapy.cfg: 项目的配置文件。
  • mySpider/: 项目的Python模块,将会从这里引用代码。
  • mySpider/items.py: 项目的目标文件。
  • mySpider/pipelines.py: 项目的管道文件。
  • mySpider/settings.py: 项目的设置文件。
  • mySpider/spiders/: 存储爬虫代码目录。

二、明确目标(mySpider/items.py)

我们打算抓取 http://www.itcast.cn/channel/teacher.shtml 网站里的所有讲师的姓名、职称和个人信息。

  1. 打开 mySpider 目录下的 items.py。
  2. Item 定义结构化数据字段,用来保存爬取到的数据,有点像 Python 中的 dict,但是提供了一些额外的保护减少错误。
  3. 可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个 Item(可以理解成类似于 ORM 的映射关系)。
  4. 接下来,创建一个 ItcastItem 类,和构建 item 模型(model)。

  5. ``` import scrapy

    class ItcastItem(scrapy.Item): name = scrapy.Field() title = scrapy.Field() info = scrapy.Field() ```

三、制作爬虫 (spiders/itcastSpider.py)

爬虫功能要分两步:

1. 爬数据

在当前目录下输入命令,将在mySpider/spider目录下创建一个名为itcast的爬虫,并指定爬取域的范围:

1
scrapy genspider itcast "itcast.cn"

打开 mySpider/spider目录里的 itcast.py,默认增加了下列代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import scrapy

class ItcastSpider(scrapy.Spider):
    name = "itcast"
    allowed_domains = ["itcast.cn"]
    start_urls = (
        'http://www.itcast.cn/',
    )

    def parse(self, response):
        pass

其实也可以由我们自行创建itcast.py并编写上面的代码,只不过使用命令可以免去编写固定代码的麻烦

要建立一个Spider, 你必须用scrapy.Spider类创建一个子类,并确定了三个强制的属性 和 一个方法。

name = "" :这个爬虫的识别名称,必须是唯一的,在不同的爬虫必须定义不同的名字。

allow_domains = [] 是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的URL会被忽略。

start_urls = () :爬取的URL元祖/列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成。

parse(self, response) :解析的方法,每个初始URL完成下载后将被调用,调用的时候传入从每一个URL传回的Response对象来作为唯一参数,主要作用如下:

负责解析返回的网页数据(response.body),提取结构化数据(生成item) 生成需要下一页的URL请求。 将start_urls的值修改为需要爬取的第一个url

1
start_urls = ("http://www.itcast.cn/channel/teacher.shtml",)

修改parse()方法

1
2
3
def parse(self, response):
    filename = "teacher.html"
    open(filename, 'w').write(response.body)

然后运行一下看看,在mySpider目录下执行:

1
scrapy crawl itcast

是的,就是 itcast,看上面代码,它是 ItcastSpider 类的 name 属性,也就是使用 scrapy genspider命令的唯一爬虫名。

运行之后,如果打印的日志出现 [scrapy] INFO: Spider closed (finished),代表执行完成。 之后当前文件夹中就出现了一个 teacher.html 文件,里面就是我们刚刚要爬取的网页的全部源代码信息。

注意: Python2.x默认编码环境是ASCII,当和取回的数据编码格式不一致时,可能会造成乱码;我们可以指定保存内容的编码格式,一般情况下,我们可以在代码最上方添加

1
2
3
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

这三行代码是 Python2.x 里解决中文编码的万能钥匙,经过这么多年的吐槽后 Python3 学乖了,默认编码是Unicode了...(祝大家早日拥抱Python3)

2. 取数据

爬取整个网页完毕,接下来的就是的取过程了,首先观察页面源码:

1
2
3
4
<div class="li_txt">
    <h3>  xxx  </h3>
    <h4> xxxxx </h4>
    <p> xxxxxxxx </p>

是不是一目了然?直接上 XPath 开始提取数据吧。

xpath 方法,我们只需要输入的 xpath 规则就可以定位到相应 html 标签节点,详细内容可以查看 xpath 教程

不会 xpath 语法没关系,Chrome 给我们提供了一键获取 xpath 地址的方法(右键->检查->copy->copy xpath),如下图:

img

这里给出一些 XPath 表达式的例子及对应的含义:

  • /html/head/title: 选择HTML文档中 <head> 标签内的 <title> 元素
  • /html/head/title/text(): 选择上面提到的 <title> 元素的文字
  • //td: 选择所有的 <td> 元素
  • //div[@class="mine"]: 选择所有具有 class="mine" 属性的 div 元素

举例我们读取网站 http://www.itcast.cn/ 的网站标题,修改 itcast.py 文件代码如下::

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# -*- coding: utf-8 -*-
import scrapy

# 以下三行是在 Python2.x版本中解决乱码问题,Python3.x 版本的可以去掉
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

class Opp2Spider(scrapy.Spider):
    name = 'itcast'
    allowed_domains = ['itcast.com']
    start_urls = ['http://www.itcast.cn/']

    def parse(self, response):
        # 获取网站标题
        context = response.xpath('/html/head/title/text()')   

        # 提取网站标题
        title = context.extract_first()  
        print(title) 
        pass

执行以下命令:

1
2
3
4
5
6
$ scrapy crawl itcast
...
...
传智播客官网-好口碑IT培训机构,一样的教育,不一样的品质
...
...

我们之前在 mySpider/items.py 里定义了一个 ItcastItem 类。 这里引入进来:

1
from mySpider.items import ItcastItem

然后将我们得到的数据封装到一个 ItcastItem 对象中,可以保存每个老师的属性:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from mySpider.items import ItcastItem

def parse(self, response):
    #open("teacher.html","wb").write(response.body).close()

    # 存放老师信息的集合
    items = []

    for each in response.xpath("//div[@class='li_txt']"):
        # 将我们得到的数据封装到一个 `ItcastItem` 对象
        item = ItcastItem()
        #extract()方法返回的都是unicode字符串
        name = each.xpath("h3/text()").extract()
        title = each.xpath("h4/text()").extract()
        info = each.xpath("p/text()").extract()

        #xpath返回的是包含一个元素的列表
        item['name'] = name[0]
        item['title'] = title[0]
        item['info'] = info[0]

        items.append(item)

    # 直接返回最后数据
    return items

我们暂时先不处理管道,后面会详细介绍。

保存数据

scrapy保存信息的最简单的方法主要有四种,-o 输出指定格式的文件,命令如下:

1
scrapy crawl itcast -o teachers.json

json lines格式,默认为Unicode编码

1
scrapy crawl itcast -o teachers.jsonl

csv 逗号表达式,可用Excel打开

1
scrapy crawl itcast -o teachers.csv

xml格式

1
scrapy crawl itcast -o teachers.xml

思考

如果将代码改成下面形式,结果完全一样。

请思考 yield 在这里的作用(Python yield 使用浅析):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# -*- coding: utf-8 -*-
import scrapy
from mySpider.items import ItcastItem

# 以下三行是在 Python2.x版本中解决乱码问题,Python3.x 版本的可以去掉
import sys
reload(sys)
sys.setdefaultencoding("utf-8")

class Opp2Spider(scrapy.Spider):
    name = 'itcast'
    allowed_domains = ['itcast.com']
    start_urls = ("http://www.itcast.cn/channel/teacher.shtml",)

    def parse(self, response):
        #open("teacher.html","wb").write(response.body).close()

        # 存放老师信息的集合
        items = []

        for each in response.xpath("//div[@class='li_txt']"):
            # 将我们得到的数据封装到一个 `ItcastItem` 对象
            item = ItcastItem()
            #extract()方法返回的都是unicode字符串
            name = each.xpath("h3/text()").extract()
            title = each.xpath("h4/text()").extract()
            info = each.xpath("p/text()").extract()

            #xpath返回的是包含一个元素的列表
            item['name'] = name[0]
            item['title'] = title[0]
            item['info'] = info[0]

            items.append(item)

        # 直接返回最后数据
        return items

原文链接:https://segmentfault.com/a/1190000013178839

img

Scrapy Shell

Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。

如果安装了 IPython ,Scrapy终端将使用 IPython (替代标准Python终端)。 IPython 终端与其他相比更为强大,提供智能的自动补全,高亮输出,及其他特性。(推荐安装IPython)

启动Scrapy Shell

进入项目的根目录,执行下列命令来启动shell:

1
scrapy shell "http://www.itcast.cn/channel/teacher.shtml"

图片描述

Scrapy Shell根据下载的页面会自动创建一些方便使用的对象,例如 Response 对象,以及 Selector 对象 (对HTML及XML内容)。

  • 当shell载入后,将得到一个包含response数据的本地 response 变量,输入 response.body将输出response的包体,输出 response.headers 可以看到response的包头。
  • 输入 response.selector 时, 将获取到一个response 初始化的类 Selector 的对象,此时可以通过使用 response.selector.xpath()response.selector.css() 来对 response 进行查询。
  • Scrapy也提供了一些快捷方式, 例如 response.xpath()response.css()同样可以生效(如之前的案例)。

Selectors选择器

Scrapy Selectors 内置 XPath 和 CSS Selector 表达式机制

Selector有四个基本的方法,最常用的还是xpath:

  • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表
  • extract(): 序列化该节点为Unicode字符串并返回list
  • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表,语法同 BeautifulSoup4
  • re(): 根据传入的正则表达式对数据进行提取,返回Unicode字符串list列表

XPath表达式的例子及对应的含义:

1
2
3
4
/html/head/title: 选择<HTML>文档中 <head> 标签内的 <title> 元素
/html/head/title/text(): 选择上面提到的 <title> 元素的文字
//td: 选择所有的 <td> 元素
//div[@class="mine"]: 选择所有具有 class="mine" 属性的 div 元素

尝试Selector

我们用腾讯社招的网站http://hr.tencent.com/positio...举例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 启动
scrapy shell "http://hr.tencent.com/position.php?&start=0#a"

# 返回 xpath选择器对象列表
response.xpath('//title')
[<Selector xpath='//title' data=u'<title>\u804c\u4f4d\u641c\u7d22 | \u793e\u4f1a\u62db\u8058 | Tencent \u817e\u8baf\u62db\u8058</title'>]

# 使用 extract()方法返回 Unicode字符串列表
response.xpath('//title').extract()
[u'<title>\u804c\u4f4d\u641c\u7d22 | \u793e\u4f1a\u62db\u8058 | Tencent \u817e\u8baf\u62db\u8058</title>']

# 打印列表第一个元素,终端编码格式显示
print response.xpath('//title').extract()[0]
<title>职位搜索 | 社会招聘 | Tencent 腾讯招聘</title>

# 返回 xpath选择器对象列表
response.xpath('//title/text()')
<Selector xpath='//title/text()' data=u'\u804c\u4f4d\u641c\u7d22 | \u793e\u4f1a\u62db\u8058 | Tencent \u817e\u8baf\u62db\u8058'>

# 返回列表第一个元素的Unicode字符串
response.xpath('//title/text()')[0].extract()
u'\u804c\u4f4d\u641c\u7d22 | \u793e\u4f1a\u62db\u8058 | Tencent \u817e\u8baf\u62db\u8058'

# 按终端编码格式显示
print response.xpath('//title/text()')[0].extract()
职位搜索 | 社会招聘 | Tencent 腾讯招聘

response.xpath('//*[@class="even"]')
职位名称:

print site[0].xpath('./td[1]/a/text()').extract()[0]
TEG15-运营开发工程师(深圳)
职位名称详情页:

print site[0].xpath('./td[1]/a/@href').extract()[0]
position_detail.php?id=20744&keywords=&tid=0&lid=0
职位类别:

print site[0].xpath('./td[2]/text()').extract()[0]
技术类

以后做数据提取的时候,可以把现在Scrapy Shell中测试,测试通过后再应用到代码中。

当然Scrapy Shell作用不仅仅如此,但是不属于我们课程重点,不做详细介绍。

官方文档:[http://scrapy-chs.readthedocs...

Item Pipeline

当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。

每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:

  • 验证爬取的数据(检查item包含某些字段,比如说name字段)
  • 查重(并丢弃)
  • 将爬取结果保存到文件或者数据库中

编写item pipeline

编写item pipeline很简单,item pipiline组件是一个独立的Python类,其中process_item()方法必须实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import something

class SomethingPipeline(object):
    def __init__(self):    
        # 可选实现,做参数初始化等
        # doing something

    def process_item(self, item, spider):
        # item (Item 对象) – 被爬取的item
        # spider (Spider 对象) – 爬取该item的spider
        # 这个方法必须实现,每个item pipeline组件都需要调用该方法,
        # 这个方法必须返回一个 Item 对象,被丢弃的item将不会被之后的pipeline组件所处理。
        return item

    def open_spider(self, spider):
        # spider (Spider 对象) – 被开启的spider
        # 可选实现,当spider被开启时,这个方法被调用。

    def close_spider(self, spider):
        # spider (Spider 对象) – 被关闭的spider
        # 可选实现,当spider被关闭时,这个方法被调用

启用一个Item Pipeline组件

为了启用Item Pipeline组件,必须将它的类添加到 settings.py文件ITEM_PIPELINES 配置,就像下面这个例子:

1
2
3
4
5
6
# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    #'mySpider.pipelines.SomePipeline': 300,
    "mySpider.pipelines.ItcastJsonPipeline":300
}

分配给每个类的整型值,确定了他们运行的顺序,item按数字从低到高的顺序,通过pipeline,通常将这些数字定义在0-1000范围内(0-1000随意设置,数值越低,组件的优先级越高)

重新启动爬虫

将parse()方法改为入门简介中最后思考中的代码,然后执行下面的命令:

1
scrapy crawl itcast

查看当前目录是否生成teacher.json

img

Settings

Scrapy设置(settings)提供了定制Scrapy组件的方法。可以控制包括核心(core),插件(extension),pipeline及spider组件。比如 设置Json Pipeliine、LOG_LEVEL等。

参考文档:http://scrapy-chs.readthedocs...


内置设置参考手册

  • BOT_NAME

    • 默认: 'scrapybot'
    • 当您使用 startproject 命令创建项目时其也被自动赋值。
  • CONCURRENT_ITEMS

    • 默认: 100
    • Item Processor(即 Item Pipeline) 同时处理(每个response的)item的最大值。
  • CONCURRENT_REQUESTS

    • 默认: 16
    • Scrapy downloader 并发请求(concurrent requests)的最大值。
  • DEFAULT_REQUEST_HEADERS

    • 默认: 如下

      { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept-Language': 'en', }

​ Scrapy HTTP Request使用的默认header。

  • DEPTH_LIMIT

    • 默认: 0
    • 爬取网站最大允许的深度(depth)值。如果为0,则没有限制。
  • DOWNLOAD_DELAY

    • 默认: 0

    • 下载器在下载同一个网站下一个页面前需要等待的时间。该选项可以用来限制爬取速度, 减轻服务器压力。同时也支持小数:

      DOWNLOAD_DELAY = 0.25 # 250 ms of delay

    • 默认情况下,Scrapy在两个请求间不等待一个固定的值, 而是使用0.5到1.5之间的一个随机值 DOWNLOAD_DELAY 的结果作为等待间隔。

  • DOWNLOAD_TIMEOUT

    • 默认: 180
    • 下载器超时时间(单位: 秒)。
  • ITEM_PIPELINES

    • 默认: {}
    • 保存项目中启用的pipeline及其顺序的字典。该字典默认为空,值(value)任意,不过值(value)习惯设置在0-1000范围内,值越小优先级越高。
1
2
3
4
            ITEM_PIPELINES = {
            'mySpider.pipelines.SomethingPipeline': 300,
            'mySpider.pipelines.ItcastJsonPipeline': 800,
            }
  • LOG_ENABLED

    • 默认: True
    • 是否启用logging。
  • LOG_ENCODING

    • 默认: 'utf-8'
    • logging使用的编码。
  • LOG_LEVEL

    • 默认: 'DEBUG'
    • log的最低级别。可选的级别有: CRITICAL、 ERROR、WARNING、INFO、DEBUG 。
  • USER_AGENT

    • 默认: "Scrapy/VERSION (+http://scrapy.org)"
    • 爬取的默认User-Agent,除非被覆盖。
  • PROXIES: 代理设置

    • 示例:

      PROXIES = [ {'ip_port': '111.11.228.75:80', 'password': ''}, {'ip_port': '120.198.243.22:80', 'password': ''}, {'ip_port': '111.8.60.9:8123', 'password': ''}, {'ip_port': '101.71.27.120:80', 'password': ''}, {'ip_port': '122.96.59.104:80', 'password': ''}, {'ip_port': '122.224.249.122:8088', 'password':''}, ]

  • COOKIES_ENABLED = False

    • 禁用Cookies

scrapy爬虫框架(一):scrapy框架简介

一、安装scrapy框架

1
2
#打开命令行输入如下命令:
pip install scrapy

二、创建一个scrapy项目

安装完成后,python会自动将 scrapy命令添加到环境变量中去,这时我们就可以使用 scrapy命令来创建我们的第一个 scrapy项目了。

打开命令行,输入如下命令

1
scrapy startproject yourproject

这里的 startproject 命令将会在当前目录下创建一个 scrapy项目,后面跟着的参数是需要创建的项目的名称。

比如这里我们会创建一个名为 yourproject 的项目,项目结构如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
yourproject/
    scrapy.cfg
    yourproject/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

这些文件分别是:

  • scrapy.cfg: 项目的配置文件
  • yourproject/: 该项目的python模块。该项目的所有代码都在这个目录下
  • yourproject/items.py: 项目中的item文件,我们在这个文件里定义要爬取的数据,有点类似于 Django的 model。
  • yourproject/pipelines.py:项目中的pipelines文件(我把这个称为通道文件,意思就是数据处理的通道),对爬取到的数据进行处理(如:储存)
  • yourproject/settings.py: 项目的设置文件,设置全局变量的值、通道的开启和关闭以及多个通道和爬虫的执行优先级
  • yourproject/spiders/: 爬虫的主要逻辑都在这个文件夹里,包括页面请求、数据提取、反爬措施等。

scrapy爬虫框架(二):创建一个scrapy爬虫

在创建新的scrapy爬虫之前,我们需要先了解一下创建一个scrapy爬虫的基本步骤

1
scrapy startproject douban

image-20200714153445972

一、确定要爬取的数据(项目名douban)

以爬取豆瓣电影数据为例: 每部电影所要爬取的信息有:(在items.py中进行数据的配置)

  • 片名:《头号玩家》
  • 导演: 史蒂文·斯皮尔伯格
  • 编剧: 扎克·佩恩 / 恩斯特·克莱恩
  • 主演: 泰伊·谢里丹 / 奥利维亚·库克 / 本·门德尔森 / 马克·里朗斯 / 丽娜·维特 / 更多...
  • 类型: 动作 / 科幻 / 冒险

所以items文件的代码如下:

1
2
3
4
5
6
7
8
class DoubanItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    movie_name = scrapy.Field()  #电影名
    movie_dir = scrapy.Field()  #导演
    movie_editors = scrapy.Field() #编剧
    movie_actors = scrapy.Field() #主演
    movie_type = scrapy.Field() #类型

二、爬取所需的信息

确定了要爬取的信息后,就可以开始写爬虫的代码了。

首先,我们创建一个爬虫文件。

在命令行中输入如下命令(必须在爬虫项目的文件夹里):

1
2
3
scrapy genspider spidername "domain"
#spidername是要创建的爬虫的名字必须是唯一的而且不能和爬虫项目名相同
#domain是要爬取的网站的 host即你所要爬取的网站的域名,www.baidu.com

这里使用的是:

1
scrapy genspider movieInfoSpider "movie.douban.com"

image-20200714153625658

创建好爬虫文件后,打开爬虫项目下的spiders文件夹,用编辑器打开我们刚刚创建的爬虫文件。

文件里已经定义好了start_urls,这是我们运行爬虫时要访问的链接。

注意这是一个列表,可以放入多个url。

当爬虫运行时就会一个一个地访问 start_urls里的链接,然后将返回的响应做为参数传递给 parse函数。

在 parse函数里,我们可以来对网页中的信息进行提取。

示例只爬取一个页面(头号玩家的详情页),代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# -*- coding: utf-8 -*-
#movieInfoSpider.py
import scrapy
#导入DouBanItem类
from douban.items import DoubanItem

class MovieinfoSpider(scrapy.Spider):
    name = 'movieInfo'
    allowed_domains = ['movie.douban.com']
    start_urls = ['https://movie.douban.com/subject/4920389/?from=showing']

    def parse(self, response):
        #创建DoubanItem类
        item = DoubanItem()

        item['movie_name'] = response.xpath('//title/text()').extract()[0]
        item['movie_dir'] = '导演:' + '/'.join(response.xpath('//div[@id="info"]/span[1]/span/a/text()').extract())
        item['movie_editors'] = '编剧:' + '/'.join(response.xpath('//div[@id="info"]/span[2]/span/a/text()').extract())
        item['movie_actors'] = '主演:' + '/'.join(response.xpath('//div[@id="info"]/span[3]/span/a/text()').extract())
        item['movie_type'] = '类型:' + '/'.join(response.xpath('//div[@id="info"]/span[@property=

        yield item

提取到所需的信息后,用 yield 关键字将 item传递给 pipelines.py进行进一步的处理

三、对提取到的信息进行储存

pipelines.py文件获得item后将会调用管道函数来对item进行处理,这里我们把电影的信息保存到 txt文件中去,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# -*- coding: utf-8 -*-
#pipelines.py

class DoubanPipeline(object):
    def __init__(self):
        self.fo = open('info.txt', 'wb')

    def process_item(self, item, spider):
        self.fo.write((item['movie_name'] + '\n').encode('utf-8'))
        self.fo.write((item['movie_dir'] + '\n').encode('utf-8'))
        self.fo.write((item['movie_editor'] + '\n').encode('utf-8'))
        self.fo.write((item['movie_actors'] + '\n').encode('utf-8'))
        self.fo.write((item['movie_type'] + '\n').encode('utf-8'))

        #这里必须返回item,否则程序会一直等待,直到返回item为止
        return item

    def close_spider(self, spider):
        self.fo.close()
    #__init__, 和close_spider 函数相当于c++里的构造函数和析构函数

四、在 setting.py里开启 DoubanPipeline管道

这里只截取部分相关的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Obey robots.txt rules
#是否遵循网站对爬虫的规则,一般设为False,但默认为True
ROBOTSTXT_OBEY = False

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'douban.pipelines.DoubanPipeline': 300,
}

#设置请求头,模拟浏览器
# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'

# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
'Cookie': 'bid=uzUipzgnxdY; ll="118267"; __utmc=30149280; __utmz=30149280.1523088054.4.4.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __utmc=223695111; __utmz=223695111.1523088054.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; __yadk_uid=u46EFxFlzD46PvWysMULc80N9s8k2pp4; _vwo_uuid_v2=DC94F00058615E2C6A432CB494EEB894B|64bbcc3ac402b9490e5de18ce3216c5f; _pk_ref.100001.4cf6=%5B%22%22%2C%22%22%2C1523092410%2C%22https%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DFIqLEYPF6UnylF-ja19vuuKZ51u3u5gGYJHpVJ5MRTO-oLkJ_C84HBgYi5OulPwl%26wd%3D%26eqid%3Dd260482b00005bbb000000055ac87ab2%22%5D; _pk_id.100001.4cf6=cbf515d686eadc0b.1523088053.2.1523092410.1523088087.; _pk_ses.100001.4cf6=*; __utma=30149280.1054682088.1514545233.1523088054.1523092410.5; __utmb=30149280.0.10.1523092410; __utma=223695111.979367240.1523088054.1523088054.1523092410.2; __utmb=223695111.0.10.1523092410',
'Host': 'movie.douban.com',
'Upgrade-Insecure-Requests': '1',
}

五、运行爬虫

进入到爬虫项目的文件夹里执行如下命令:

1
scrapy crawl movieInfo   

注意这里的名字是image-20200714160007401

要是用错了就会报错

总结:scrapy爬虫构建顺序 items.py→spiders→pipelines.py→settings.py

原文: https://blog.csdn.net/qq_40695895/article/details/79842502

scrapy爬虫框架(三):爬取壁纸保存并命名

写在开始之前

按照上一篇介绍过的 scrapy爬虫的创建顺序,我们开始爬取壁纸的爬虫的创建。

首先,我们先过一遍 scrapy爬虫的创建顺序:

  • 第一步:确定要在pipelines里进行处理的数据,写好items文件
  • 第二步:创建爬虫文件,将所需要的信息从网站上爬取下来,并传递给pipelines文件处理
  • 第三步:pipelines接收spiders传递过来的数据,并做出相应的处理,如:壁纸的下载和保存
  • 第四步:一定要记得在settings开启pipelines

在开始之前,我们先按照上面的步骤来分析一下代码怎么写:

  1. 第一步:确定我们要爬取的网站,在百度上随便找一个, zolhttp://desk.zol.com.cn/dongman/1920x1080/, 这是zol的动漫板块,自己练手的话可以另外找一个。

  2. 第二步:确定items,我们要下载壁纸并且按照网站上的名字进行命名。

    下载壁纸需要获取壁纸的链接 image_url,命名需要壁纸的名字 image_name

  3. 第三步:编写spiders的代码从网页中获取我们image_url和image_name

  4. 第四步:下载图片并命名保存

  5. 第五步:到settings里开启pipelines

下面正式开始敲代码<( ̄︶ ̄)↗[GO!]

一、创建scrapy爬虫项目

打开命令行,依次输入如下命令:

1
2
3
4
5
6
#创建scrapy爬虫项目
scrapy startproject bizhi_zol
#打开新创建的爬虫项目
cd bizhi_zol
#在项目里创建spidersdomain为desk.zol.com.cn
scrapy genspider zol "desk.zol.com.cn"

二、items.py

项目创建完成后,我们按照上面的顺序,先写items

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# -*- coding: utf-8 -*-
#items.py

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy

class BizhiZolItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    image_url = scrapy.Field()  #图片的地址
    image_name = scrapy.Field() # 图片的名字

三、spiders

这一步可以说是整个爬虫里最重要的一步了

首先我们先分析网页结构,打开网址:http://desk.zol.com.cn/dongman/1920x1080/

查看元素后发现壁纸链接全在ul标签下

xpath路径如下:

1
2
3
#注意!!!
#pic-list2(两个空格)clearfix
//ul[@class="pic-list2  clearfix"]/li/a

通过xpath我们得到的是壁纸下载页面的链接

再通过链接获取壁纸下载页面,再在下载页面内获得壁纸链接和名字

细节不再赘述,xpath路径如下:

1
2
3
4
5
6
7
8
#内容详情页 获取壁纸名字
//a[@id="titleName"]/text()
#内容详情页 获取壁纸下载页面
#//dd[@id="tagfbl"]/a[@id="1920x1200"]/@href
//dd[@id="tagfbl"]/a[1]/@href

#壁纸下载页 获取壁纸下载链接
//body/img[1]/@src

spiders代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# -*- coding: utf-8 -*-
#zol.py

import scrapy
from bizhi_zol.items import BizhiZolItem

class ZolSpider(scrapy.Spider):
    name = 'zol'
    #allowed_domains = ['desk.zol.com.cn']
    start_urls = ['http://desk.zol.com.cn/dongman/1920x1080/']

    #主站链接 用来拼接网址
    base_site = 'http://desk.zol.com.cn'

    def parse(self, response):
        #获取内容详情页链接
        load_page_urls = response.xpath('//ul[@class="pic-list2  clearfix"]/li/a/@href').extract()

        for load_page_url in load_page_urls:
            url = self.base_site + load_page_url
            #获取内容详情页页面 交给getInfo处理
            print(url)
            yield scrapy.Request(url, callback=self.getInfo)

    def getInfo(self, response):
        #定义item储存信息
        item = BizhiZolItem()
        #获取壁纸名字
        item['image_name'] = response.xpath('//a[@id="titleName"]/text()').extract()[0]
        print(item['image_name'])

        #获取壁纸下载页面链接
        #load_page = self.base_site + response.xpath('//dd[@id="tagfbl"]/a[@id="1920x1200"]/@href').extract()[0]
        #测试时发现并不是所有的壁纸都有1920x1200的分辨率,所以将代码修改如下,获得壁纸最大分辨率的链接
        load_page = self.base_site + response.xpath('//dd[@id="tagfbl"]/a[1]/@href').extract()[0]

        #获取壁纸下载页面 并将item作为参数传递给getLoadUrl
        request = scrapy.Request(load_page, callback=self.getLoadUrl)
        request.meta['item'] = item

        yield request

    def getLoadUrl(self, response):
        #接收参数
        item = response.meta['item']

        #获取壁纸下载链接
        item['image_url'] = response.xpath('//body/img[1]/@src').extract()[0]

        #将item传递给pipelines处理
        yield item

四、pipelines.py

我们已经通过 spiders获得了图片的名字和链接,接下来我们只要下载图片然后再命名保存即可。

下载图片和之前的下载小说不同,这里要用到 ImagesPipeline中的 get_media_requests 方法来进行下载。

这里简单介绍一下get_media_requests方法:

选中get_media_requests然后转到定义,可以看到get_media_requests方法的原型为:

1
2
def get_media_requests(self, item, info):
        return [Request(x) for x in item.get(self.images_urls_field, [])]

可以看到get_media_requests有三个参数,

第一个是self,这个不必多说;

第二个是 item,这个就是 spiders传递过来的 item

第三个是 info,看名字就知道这是用来保存信息的,至于是什么信息,info其实是一个用来保存保存图片的名字和下载链接的列表

但是我们想要重命名的话必须得有图片的路径,这时候就需要 item_completed方法了,原型如下:

1
2
3
4
def item_completed(self, results, item, info):
        if isinstance(item, dict) or self.images_result_field in item.fields:
            item[self.images_result_field] = [x for ok, x in results if ok]
        return item

注意到 item_completed里有个 results参数,results参数保存了图片下载的相关信息,我们将它打印出来看看:

1
[(True, {'url': 'https://desk-fd.zol-img.com.cn/t_s1920x1200c5/g5/M00/01/04/ChMkJ1q2H1-IDTMjAAT0D9iUubUAAm_uwJN1eoABPQn240.jpg', 'path': 'full/fedfedc2f28c22996af50ff8d4759e7031950517.jpg', 'checksum': '06bde14f40a64c288bd251ebbe17bc1e'})]

了解了这些后,问题就简单了。

我们只需要在 get_media_requestsscrapy.Request() 发起请求,然后 scrapy会自动将图片下载并保存。

当图片下载完成之后,我们再对图片重命名即可。

代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# -*- coding: utf-8 -*-
#pipelines.py

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html

from scrapy.pipelines.images import ImagesPipeline
from bizhi_zol.settings import IMAGES_STORE as image_store
import scrapy
import os


class BizhiZolPipeline(ImagesPipeline):
    def get_media_requests(self, item, info):
        #发起壁纸下载请求
        yield scrapy.Request(item['image_url'])

    def item_completed(self, results, item, info):
        #对壁纸进行重命名
        os.rename(image_store + '/' + results[0][1]['path'], image_store + '/' + item['image_name'] + '.jpg')

    def __del__(self):
        #完成后删除full目录
        os.removedirs(image_store + '/' + 'full')

五、settings.py

这里 settings文件需要注意的是,要添加一个 IMAGES_STORE变量来设置图片下载的目录,其他的设置不再多说,贴上代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#settings.py

BOT_NAME = 'bizhi_zol'

SPIDER_MODULES = ['bizhi_zol.spiders']
NEWSPIDER_MODULE = 'bizhi_zol.spiders'

IMAGES_STORE = './IMAGE'

# Crawl responsibly by identifying yourself (and your website) on the user-agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'

# Obey robots.txt rules
ROBOTSTXT_OBEY = False

# Configure item pipelines
# See https://doc.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'bizhi_zol.pipelines.BizhiZolPipeline': 300,
}

写到这里整个爬虫程序就完成了,不过这个爬虫程序只能爬取一页的壁纸,不能够自动翻页。

要实现自动翻页,就留给读者自己动脑筋了

ps: 自动翻页很简单,只需在原来代码的基础上增加几行代码就可以了

image-20200714164722030

image-20200714164742782

六进行爬取

1
scrapy crawl zol

scrapy爬虫框架(四):scrapy中 yield使用详解

开始前的准备工作:

MySQL下载:点我 python MySQL驱动下载:pymysql(pyMySql,直接用pip方式安装)

全部安装好之后,我们来熟悉一下pymysql模块

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import pymysql

#创建链接对象
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python')
#创建游标 游标用来进行查询,修改等操作
cursor = connection.cursor()

#定义sql语句 这里的sql语法根据使用的数据库不同会有一些小差别
sql = "SELECT * FROM python.text_info where text_title='test'"

#执行sql语句 返回受到影响的行数
cursor.execute(sql)

#获取sql语句执行后的返回数据 默认返回的数据类型为元组
#获取所有返回
r = cursor.fetchall()
#获取一个返回
r = cursor.fetchone()
#获取至多三个返回 不足三个时返回所有
r = cursor.fetchmany(3)
#其他的fetch方法可自行百度

#将返回数据类型改为字典
cursor = connection.cursor(cursor=pymysql.cursors.DictCursor)
#或者在创建连接对象时指定返回数据类型为字典 建议把返回类型修改为字典类型
connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python', cursorclass=pymysql.cursors.DictCursor)

#保存所做的修改 在连接关闭之前,如果你没有调用下面的语句
#那么,你之前的所有修改将不会被保存
connection.commit()

#关闭游标
cursor.close()
#关闭连接
connection.close()

一、确定items

我们要爬取的网站是:http://m.50zw.la(网址打不开了,参考翻页的代码以及对数据库的操作即可) 要爬取的是小说的信息,如图:

img

所以items.py文件如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import scrapy


class TextInfoItem(scrapy.Item):
    # name = scrapy.Field()
    text_name = scrapy.Field()
    text_author = scrapy.Field()
    text_type = scrapy.Field()
    text_status = scrapy.Field()
    text_latest = scrapy.Field()
    text_intro = scrapy.Field()

最后信息是要储存到数据库里的,所以我们还得创建一个数据库表。

  • 第一步:在开始菜单里找到MySQL Workbench,双击打开。MySQL Workbench是MySQL自带的一个可视化管理工具
  • 第二步:在 MySQL Workbench里连接数据库,并创建一个数据库 python,然后再在刚刚创建的数据库里创建一个表 text_info
  • 第三步:在 text_info表里逐一添加 text_name,text_author 等属性,类型全部设置为 varchar,大小除了 text_intro是 1000外,其他的全部设置为 50

MySQL的使用就不详细讲了。如果遇到问题,欢迎评论留言。

二、爬取信息

为了简单,我们只爬取 50zw网站下的玄幻分类的小说信息。

细节前面已经讲过了,这里不再多讲,有不懂的可以去看前面的几篇文章。

废话不多说,直接上代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import scrapy
from text_info.items import TextInfoItem

class A50zwSpider(scrapy.Spider):
    name = '50zw'
    allowed_domains = ['m.50zw.la']
    start_urls = ['http://m.50zw.la/wapsort/1_1.html']

    #主站链接 用来拼接
    base_site = 'http://m.50zw.la'

    def parse(self, response):
        book_urls = response.xpath('//table[@class="list-item"]//a/@href').extract()

        for book_url in book_urls:
            url = self.base_site + book_url
            yield scrapy.Request(url, callback=self.getInfo)

        #获取下一页
        next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一页")]/@href').extract()[0]
        yield scrapy.Request(next_page_url, callback=self.parse)

    def getInfo(self, response):
        item = TextInfoItem()

        #提取信息
        item['text_id'] = response.url.split('_')[1].replace('/', '')
        item['text_name'] = response.xpath('//table[1]//p/strong/text()').extract()[0]
        item['text_author'] = response.xpath('//table[1]//p/a/text()').extract()[0]
        item['text_type'] = response.xpath('//table[1]//p/a/text()').extract()[1]
        item['text_status'] = response.xpath('//table[1]//p/text()').extract()[2][3:]
        item['text_latest'] = response.xpath('//table[1]//p[5]/text()').extract()[0][3:]
        item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]

        yield item

这里我们通过 yield 来发起一个请求,并通过 callback 参数为这个请求添加回调函数,在请求完成之后会将响应作为参数传递给回调函数。

scrapy框架会根据 yield 返回的实例类型来执行不同的操作,如果是 scrapy.Request 对象,scrapy框架会去获得该对象指向的链接并在请求完成后调用该对象的回调函数。

如果是 scrapy.Item 对象,scrapy框架会将这个对象传递给 pipelines.py做进一步处理。

这里我们有三个地方使用了 yield ,第一个地方是:

1
2
3
 for book_url in book_urls:
        url = self.base_site + book_url
        yield scrapy.Request(url, callback=self.getInfo)

这里我们在循环里不断提取小说详细页面的链接,并通过 yield 来发起请求,并且还将函数 getInfo 作为回调函数来从响应中提取所需的数据。

第二个地方是:

1
2
3
#获取下一页
next_page_url = self.base_site + response.xpath('//table[@class="page-book"]//a[contains(text(),"下一页")]/@href').extract()[0]
yield scrapy.Request(next_page_url, callback=self.parse)

这里是在爬取完一页的信息后,我们在当前页面获取到了下一页的链接,然后通过 yield 发起请求,并且将 parse 自己作为回调函数来处理下一页的响应。

这有点像递归,不过递归是函数自己调用自己,这里看起来好像是 parse 调用了自己,但实际上 parse 是由 scrapy框架在获得响应后调用的。

最后一处使用了 yield 的地方在 getInfo 函数里:

1
2
3
4
5
6
7
def getInfo(self, response):
        item = TextInfoItem()

        ... ...

        item['text_intro'] = response.xpath('//div[@class="intro"]/text()').extract()[0]
        yield item

这里我们通过 yield 返回的不是 Request 对象,而是一个 TextInfoItem 对象。

scrap有框架获得这个对象之后,会将这个对象传递给 pipelines.py来做进一步处理。

我们将在 pipelines.py里将传递过来的 scrapy.Item 对象保存到数据库里去。

三、将信息插入数据库

python对数据库的操作很简单,我们简单了解一下步骤:

  1. 建立数据库连接
  2. 创建操作游标
  3. 写sql语句
  4. 执行sql语句
  5. 如果执行的是查询语句,则用fetch语句获取查询结果
  6. 如果执行的是插入、删除等对数据库造成了影响的sql语句,还需要执行commit保存修改

贴上代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import pymysql

class TextInfoPipeline(object):
    def __init__(self):
        #建立数据库连接
        self.connection = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='1234', db='python',charset='utf8')
        #创建操作游标
        self.cursor = self.connection.cursor()

    def process_item(self, item, spider):
        #定义sql语句
        sql = "INSERT INTO `python`.`text_info` (`text_id`, `text_name`, `text_author`, `text_type`, `text_status`, `text_latest`, `text_intro`) VALUES ('"+item['text_id']+"', '"+item['text_name']+"', '"+item['text_author']+"', '"+item['text_type']+"', '"+item['text_status']+"', '"+item['text_latest']+"', '"+item['text_intro']+"');"

        #执行sql语句
        self.cursor.execute(sql)
        #保存修改
        self.connection.commit()

        return item

    def __del__(self):
        #关闭操作游标
        self.cursor.close()
        #关闭数据库连接
        self.connection.close()

写在最后:

  1. 代码敲好后不要忘记在settings里开启pipelines
  2. pymsql连接时默认的编码是latin-1,所以在建立数据库连接时会增加参数charset来修改编码,要修改为utf-8的话得用charset=’utf8‘,而不是charset=’utf-8‘
  3. 这个网站有些问题,会时不时报404错误,所以在爬的过程中会报list index out of range,这是因为得到了错误的网页,xpath找不到对应得路径返回了空列表。这是正常现象,并不是代码出问题了(当然,如果频繁报错最好是检查一下代码)

贴一张成功后的图片:

img

最后的最后,觉得我写的不错的话记得关注我哦。

scrapy的暂停与重启

在爬取大型站点的时候,或遇到某些特殊情况的时候,往往需要赞同爬虫,并稍后再接着之前执行到的位置继续爬取,而不是每次出问题都从头开始。 scrapy的暂停与重启的设置很简单: 1.创建工作目录

  • 在当前项目下,创建工作目录(文件夹),命名如:crawls
  • 不同的spider是不能用同一个目录的。 该工作目录是用来保存运行中的爬虫的必须数据,以保持作业状态的。

2.用以下命令启动爬虫

1
scrapy crawl somespider -s JOBDIR=crawls/somespider-1

上述命令中: somespider: 启动的爬虫名 crawls/somespider-1:你创建的工作目录+爬虫序号

后面的somespider-1是用来区分不同的爬虫的,因为官方文档提到了:

要启用持久性支持,您只需通过JOBDIR设置定义作业目录。该目录将用于存储所有必需的数据以保持单个作业的状态(即蜘蛛运行)。重要的是要注意,此目录不能由不同的蜘蛛共享,甚至不能由同一个蜘蛛的不同作业/运行共享,因为它意味着用于存储单个作业的状态

3.暂停爬虫

以上两步,爬虫便可以能暂停的状态运行,当你需要暂停的时候,只需在运行窗口发送暂停命令即可: ctrl + c tips:

  • 只能按一次该命令,按两次的话爬虫会被强制退出。
  • 爬虫程序不会立刻暂停,它需要处理完已经发送出的请求完成善后工作,需要耐心等待一会儿。

4.暂停后的重启

输入与启动相同的命令即可:

1
scrapy crawl somespider -s JOBDIR=crawls/somespider-1

然后爬虫就会接着上一次暂停后的位置继续运行。